#pragma once

#include "HookApi.h"
#include <windows.h>
#include <detours.h>
#include <cstdio>
#include <xlocale>
#include "ImageManager.h"

HMODULE ogllib = nullptr;

pglTexImage2D pglTexImage2D_old = nullptr;
pglTexSubImage2D pglTexSubImage2D_old = nullptr;
pglBindTexture pglBindTexture_old = nullptr;
pglDeleteTextures pglDeleteTextures_old = nullptr;

pglCompressedTexImage2D pglCompressedTexImage2D_old = nullptr;
pglCompressedTexSubImage2D pglCompressedTexSubImage2D_old = nullptr;

int textureid = 0;

void HookApi() {
    DetourRestoreAfterWith();
    ogllib = LoadLibraryA("D:\\Program Files\\TxGameAssistant\\UI\\libGLESv2.dll");
    if (ogllib)
    {
        pglTexImage2D_old = (pglTexImage2D)GetProcAddress(ogllib, "glTexImage2D");
        pglTexSubImage2D_old = (pglTexSubImage2D)GetProcAddress(ogllib, "glTexSubImage2D");
        pglBindTexture_old = (pglBindTexture)GetProcAddress(ogllib, "glBindTexture");
        pglDeleteTextures_old = (pglDeleteTextures)GetProcAddress(ogllib, "glDeleteTextures");
        pglCompressedTexImage2D_old = (pglCompressedTexImage2D)GetProcAddress(ogllib, "glCompressedTexImage2D");
        pglCompressedTexSubImage2D_old = (pglCompressedTexSubImage2D)GetProcAddress(ogllib, "glCompressedTexSubImage2D");
    }


    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)pglTexImage2D_old, glTexImage2D_new);
    DetourAttach(&(PVOID&)pglTexSubImage2D_old, glTexSubImage2D_new);
    DetourAttach(&(PVOID&)pglBindTexture_old, glBindTexture_new);
    DetourAttach(&(PVOID&)pglDeleteTextures_old, glDeleteTextures_new);

    DetourAttach(&(PVOID&)pglCompressedTexImage2D_old, glCompressedTexImage2D_new);
    DetourAttach(&(PVOID&)pglCompressedTexSubImage2D_old, glCompressedTexSubImage2D_new);
    if(DetourTransactionCommit() == NO_ERROR) {
        OutputDebugStringA("hook success \n");
    }
}

void UnhookApi() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&(PVOID&)pglTexImage2D_old, glTexImage2D_new);
    DetourDetach(&(PVOID&)pglTexSubImage2D_old, glTexSubImage2D_new);
    DetourDetach(&(PVOID&)pglBindTexture_old, glBindTexture_new);
    DetourDetach(&(PVOID&)pglDeleteTextures_old, glDeleteTextures_new);

    DetourDetach(&(PVOID&)pglCompressedTexImage2D_old, glCompressedTexImage2D_new);
    DetourDetach(&(PVOID&)pglCompressedTexSubImage2D_old, glCompressedTexSubImage2D_new);
    if(DetourTransactionCommit() == NO_ERROR) {
        OutputDebugStringA("unhook success \n");
    }

    if (ogllib)
    {
        FreeLibrary(ogllib);
    }
}


void GL_APIENTRY glTexImage2D_new(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
    
    OutputDebugStringA("glTexImage2D_new\n");
    ImageManager::Instance().NewImage(textureid, width, height, format, type, pixels);
    return pglTexImage2D_old(target, level, internalformat, width, height, border, format, type, pixels);
}

void GL_APIENTRY glTexSubImage2D_new(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
    OutputDebugStringA("glTexSubImage2D_new\n");
    ImageManager::Instance().UpdateImage(textureid, xoffset, yoffset, width, height, format, type, pixels);
    return pglTexSubImage2D_old(target, level, xoffset, yoffset, width, height, format, type, pixels);
}

void GL_APIENTRY glBindTexture_new(GLenum target, GLuint texture) {

    char temp[1024] = { 0 };
    sprintf_s(temp, sizeof(temp), "glBindTexture_new target %x texture %d \n", target, texture);
    OutputDebugStringA(temp);
    textureid = texture;
    return pglBindTexture_old(target, texture);
}

void GL_APIENTRY glDeleteTextures_new(GLsizei n, const GLuint* textures) {
    char temp[1024] = { 0 };
    sprintf_s(temp, sizeof(temp), "glDeleteTextures_new n %d texture %x \n", n, textures);
    OutputDebugStringA(temp);
    ImageManager::Instance().DelImage((int*)textures, n);
    return pglDeleteTextures_old(n, textures);
}


void GL_APIENTRY glCompressedTexImage2D_new(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {
    ImageManager::Instance().NewCompressedImage(textureid, level, width, height, internalformat, imageSize, data);
    return pglCompressedTexImage2D_old(target,  level,  internalformat,  width,  height,  border,  imageSize,  data);
}
void GL_APIENTRY glCompressedTexSubImage2D_new(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {
    return pglCompressedTexSubImage2D_old(target, level, xoffset, yoffset, width, height, format, imageSize, data);
}
